/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.opentripplanner.nedimporter;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import java.awt.geom.Point2D;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.geotools.geometry.DirectPosition2D;
import org.geotools.referencing.CRS;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.geometry.DirectPosition;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform;


/**
 * The main NED (National Elevation Dataset) Importer class.
 *
 * @author demory
 */

public class NEDImporter {

  private Map<String, ElevationProfile> elevProfiles;

  private Collection<NEDCoverageSource> coverageSources;
  private Collection<NEDFeatureSource> featureSources;

  public NEDImporter() {
    coverageSources = new HashSet<NEDCoverageSource>();
    featureSources = new HashSet<NEDFeatureSource>();

    elevProfiles = new HashMap<String, ElevationProfile>();
  }

  public ElevationProfile getProfile(String id) {
    return elevProfiles.get(id);
  }

  public Collection<ElevationProfile> getProfiles() {
    return elevProfiles.values();
  }

  public void addCoverageSource(NEDCoverageSource coverageSource) {
    coverageSources.add(coverageSource);
  }

  public void addFeatureSource(NEDFeatureSource featureSource) {
    featureSources.add(featureSource);
  }

  public double getElevation(GridCoverage2D coverage, double x, double y) {
    double values[] = new double[1];
    coverage.evaluate(new Point2D.Double(x, y), values);
    return values[0];
  }

  public void runOverlay(double sampleFreq) {

    for(NEDFeatureSource source: featureSources) {
      FeatureCollection fColl = source.getFeatures();
        processFeatures(fColl, sampleFreq);
    }
  }

  public void processFeatures(FeatureCollection fColl, double sampleFreq) { //URL shapeURL, String keyAttrName, double frequency) {
    try {
      
      CoordinateReferenceSystem sourceCRS = fColl.getBounds().getCoordinateReferenceSystem();
      CoordinateReferenceSystem destCRS = CRS.decode("EPSG:4269");
      //System.out.println("crs: "+sourceCRS.toString());
      MathTransform mt = CRS.findMathTransform(sourceCRS, destCRS);

      FeatureIterator fIter = fColl.features();
      int c = 0;

      NEDCoverageSource src = coverageSources.iterator().next();
      //System.out.println("covsrc="+src);
      GridCoverage2D cov = src.getCoverage();
      
      while (fIter.hasNext()) {
        c++;
        if (c % 100 == 0) {
          System.out.println("processed " + c + " features");
        }

        SimpleFeature f = (SimpleFeature) fIter.next();

        Geometry g = (Geometry) f.getDefaultGeometry();
        Coordinate[] coords = g.getCoordinates();

        System.out.println("feat id: "+f.getID());

        double current = 0, total = 0;
        ElevationProfile profile = new ElevationProfile();

        DirectPosition2D srcDP = new DirectPosition2D(coords[0].x, coords[0].y), destDP = new DirectPosition2D();
        mt.transform(srcDP, destDP);
        profile.addElevation(0, getElevation(cov, destDP.x, destDP.y));

        int freqCount = 0;
        for(int i = 0; i < coords.length-1; i++) {

          double segLen = Point2D.distance(coords[i].x, coords[i].y, coords[i+1].x, coords[i+1].y);
          //System.out.println(" dist: "+segLen);
          double last = current;
          current += segLen;
          total += segLen;
          int iterCount = 0;
          while(current > sampleFreq) {
            freqCount++;
            iterCount++;
            double distIntoSeg = sampleFreq - last;
            //System.out.println("   dIS="+distIntoSeg);
            double dx =  coords[i+1].x - coords[i].x;
            double dy =  coords[i+1].y - coords[i].y;
            double t = (distIntoSeg + iterCount * sampleFreq) / segLen;
            srcDP = new DirectPosition2D(coords[0].x + t*dx, coords[0].y + t*dy);
            mt.transform(srcDP, destDP);
            profile.addElevation(sampleFreq*freqCount, getElevation(cov, destDP.x, destDP.y));
            current -= sampleFreq;
          }
        }

        if(total % sampleFreq != 0) { // add end point
          srcDP = new DirectPosition2D(coords[coords.length-1].x, coords[coords.length-1].y);
          mt.transform(srcDP, destDP);
          profile.addElevation(total, getElevation(cov, destDP.x, destDP.y));
        }
      }
    }
    catch(Exception ex) {
      ex.printStackTrace();
    }
  }

}
